package com.hy.mvc.biz.service.manager.base;

import com.hy.mvc.domain.dataobject.base.Cache;
import org.apache.commons.lang.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.io.*;
import java.util.Map;
import java.util.Set;

/**
 * <pre>
 *    author  : Booker
 *    time    : 2017/12/11 15:17
 *    desc    : 输入描述
 *    version : v1.0
 * </pre>
 */
@Component
public class JedisCacheManager implements Cache {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JedisCacheManager.class);

    @Resource
    private JedisPool jedisPool;


    /**
     * 从cache取某个节点
     *
     * @param key
     * @return
     */
    @Override
    public <T> T get(String key) {
        return get(key, 0);
    }

    /**
     * 从cache取某个节点
     *
     * @param key
     * @return
     */
    public <T> T get(String key, int dbIndex) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        T value = fromBytes(jedis.get(key.getBytes()));
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return value;
    }


    /**
     * 选择redis库
     *
     * @param jedis
     * @param dbIndex
     */
    private void selectDB(Jedis jedis, int dbIndex) {
        if (dbIndex < 0 || dbIndex > 16) {
            jedis.select(0);
            return;
        }
        jedis.select(dbIndex);
    }

    /**
     * 从cache取计数器的值
     *
     * @param key
     * @return
     */
    @Override
    public long getCounter(String key) {
        return 0;
    }

    /**
     * 将某个节点保存到cache中
     *
     * @param key
     * @param value
     */
    @Override
    public <T> boolean set(String key, T value) {
        return set(key, value, 0);
    }

    /**
     * @param key
     * @param value
     * @param dbIndex
     * @param <T>
     * @return
     */
    public <T> boolean set(String key, T value, int dbIndex) {
        if (value == null) {
            return false;
        }
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        jedis.set(key.getBytes(), toBytes(value));
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return true;
    }

    /**
     * 写入计数器的值
     *
     * @param key
     * @param value
     * @return
     */
    @Override
    public boolean storeCounter(String key, long value) {
        return false;
    }

    /**
     * 在cache中删除某个节点
     *
     * @param key
     */
    @Override
    public boolean remove(String key) {
        return remove(key, 0);
    }

    /**
     * 从redis库移除
     *
     * @param key
     * @param dbIndex
     * @return
     */
    public boolean remove(String key, int dbIndex) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        long result = jedis.del(key);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;

        if (result == 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 是否存在这个主键的节点
     *
     * @param key
     * @return
     */
    @Override
    public boolean has(String key) {
        return has(key, 0);
    }

    /**
     * @param key
     * @param dbIndex
     * @return
     */
    public boolean has(String key, int dbIndex) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        boolean ret = jedis.exists(key);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * 得到能遍历当前cache内所有数据的迭代器
     *
     * @return null表示不支持这种操作
     */
    @Override
    public <T> Set<String> keySet() {
        return null;
    }

    /**
     * 清空cache内的数据
     *
     * @return 清除的个数，-1表示不支持这种操作
     */
    @Override
    public int clear() {
        return -1;
    }

    /**
     * 返回cache内的元素个数
     *
     * @return
     */
    @Override
    public int size() {
        return 0;
    }

    /**
     * @param key
     * @return
     */
    public Map<String, String> hgetAll(String key) {
        return hgetAll(key, 0);
    }

    /**
     * @param key
     * @param dbIndex
     * @return
     */
    public Map<String, String> hgetAll(String key, int dbIndex) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Map<String, String> ret = jedis.hgetAll(key);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param hash
     * @return
     */
    public String hmset(String key, Map<String, String> hash) {
        return hmset(key, hash, 0);
    }

    /**
     * @param key
     * @param hash
     * @param dbIndex
     * @return
     */
    public String hmset(String key, Map<String, String> hash, int dbIndex) {
        if (hash == null) {
            return StringUtils.EMPTY;
        }
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        String ret = jedis.hmset(key, hash);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param field
     * @return
     */
    public String hget(String key, String field) {
        return hget(key, field, 0);
    }

    /**
     * @param key
     * @param field
     * @param dbIndex
     * @return
     */
    public String hget(String key, String field, int dbIndex) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        String ret = jedis.hget(key, field);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param field
     * @param value
     * @return
     */
    public Long hset(String key, String field, String value) {
        return hset(key, field, value, 0);
    }

    /**
     * 清楚缓存
     *
     * @param dbIndex
     * @param flushAll
     */
    public void flushDB(int dbIndex, boolean flushAll) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        if (!flushAll) {
            jedis.flushDB();
        } else {
            jedis.flushAll();
        }
        jedis.flushDB();
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
    }

    /**
     * @param key
     * @param field
     * @param value
     * @param dbIndex
     * @return
     */
    public Long hset(String key, String field, String value, int dbIndex) {
        if (field == null || value == null) {
            return Long.valueOf(-1);
        }
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Long ret = jedis.hset(key, field, value);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param member
     * @return
     */
    public boolean sismember(String key, String member) {
        return sismember(key, member, 0);
    }

    public boolean sismember(String key, String member, int dbIndex) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        boolean ret = jedis.sismember(key, member);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param field
     * @return
     */
    public boolean hexists(String key, String field) {
        return hexists(key, field, 0);
    }

    /**
     * @param key
     * @param field
     * @param dbIndex
     * @return
     */
    public boolean hexists(String key, String field, int dbIndex) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        boolean ret = jedis.hexists(key, field);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @return
     */
    public Long scard(String key) {
        return scard(key, 0);
    }

    /**
     * @param key
     * @param dbIndex
     * @return
     */
    public Long scard(String key, int dbIndex) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Long ret = jedis.scard(key);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param members
     * @return
     */
    public Long sadd(String key, String... members) {
        return sadd(0, key, members);
    }

    public Long sadd(int dbIndex, String key, String... members) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Long ret = jedis.sadd(key, members);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param scoreMembers
     * @return
     */
    public Long zadd(String key, Map<String, Double> scoreMembers) {
        return zadd(0, key, scoreMembers);
    }

    /**
     * @param dbIndex
     * @param key
     * @param scoreMembers
     * @return
     */
    public Long zadd(int dbIndex, String key, Map<String, Double> scoreMembers) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Long ret = jedis.zadd(key, scoreMembers);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param dbIndex
     * @param key
     * @param member
     * @return
     */
    public Double zscore(int dbIndex, String key, String member) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Double ret = jedis.zscore(key, member);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @return
     */
    public Long zcard(String key) {
        return zcard(0, key);
    }

    /**
     * @param dbIndex
     * @param key
     * @return
     */
    public Long zcard(int dbIndex, String key) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Long ret = jedis.zcard(key);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param members
     * @return
     */
    public Long zrem(String key, String... members) {
        return zrem(0, key, members);
    }

    /**
     * @param dbIndex
     * @param key
     * @param members
     * @return
     */
    public Long zrem(int dbIndex, String key, String... members) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Long ret = jedis.zrem(key, members);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    /**
     * @param key
     * @param start
     * @param stop
     * @return
     */
    public Set<String> zrevrange(String key, int start, int stop) {
        return zrevrange(0, key, start, stop);
    }

    public Set<String> zrevrange(int dbIndex, String key, int start, int stop) {
        long beginTime = System.currentTimeMillis();
        Jedis jedis = jedisPool.getResource();
        selectDB(jedis, dbIndex);
        Set<String> ret = jedis.zrevrange(key, start, stop);
        jedis.close();
        long time = System.currentTimeMillis() - beginTime;
        return ret;
    }

    public Double zscore(String key, String member) {
        return zscore(0, key, member);
    }

    /**
     * 序列化
     *
     * @param value
     * @param <T>
     * @return
     */
    private <T> byte[] toBytes(T value) {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out;
        byte[] bytes = null;
        try {
            out = new ObjectOutputStream(byteOut);
            out.writeObject(value);
            bytes = byteOut.toByteArray();
        } catch (IOException e) {
            logger.error("Redis toByte fail", e);
        }
        return bytes;
    }

    /**
     * 反序列化
     *
     * @param bytes
     * @param <T>
     * @return
     */
    private <T> T fromBytes(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        T obj = null;
        try {
            ByteArrayInputStream byteIn = new ByteArrayInputStream(bytes);
            ObjectInputStream in = new ObjectInputStream(byteIn);
            obj = (T) in.readObject();
        } catch (Exception e) {
            logger.error("Redis fromByte fail", e);
        }
        return obj;
    }
}
